/*
 * Space.h
 *
 *  Created on: 2013. 9. 18.
 *      Author: jjaehuny
 */

#ifndef PROJECTZ_NLOGIC_SPACE_H_
#define PROJECTZ_NLOGIC_SPACE_H_

#include <map>
#include <vector>
#include <Network/Packet.h>
#include "Item.h"
#include "../constant.h"

namespace ProjectZ {
class User;
} /**/

namespace ProjectZ { namespace NLogic {

class Monster;
class Item;
class Party;
class Battle;
class Indexer;
class IndexerPVP;
class IndexerWorldBoss;
class IndexerNewPartyRoomV2;
class IndexerPK;

class Space
{


public:
	enum class SpaceType {
		__NONE__,
		WORLD,
		SINGLE_DUNGEION,
		PARTY_DUNGEION,
		PVP_PRACTICE,
		PVP_USER,
		BATTLEROYAL,

		NEW_PARTY_ROOM,
		NEW_PVP_ROOM,

		WORLDBOSS_SINGLE,
		WORLDBOSS_PARTY,
		WORLDBOSS_PARTY_FRIENDS,
		__MAX__,
	};

public:
	typedef std::map<int32_t, User *> 		USERTREE;
	typedef std::map<int, Monster *> 	MONSTERTREE;
	typedef std::map<uint32_t, bool>	INVITETREE;
	typedef std::map<int, Item *>		ITEMTREE;
	typedef std::vector<uint32_t>		RESERVEVECTOR;
	typedef std::vector<User *>			PKOUTPLAYUSERVECTOR;

	typedef std::map<int, Battle *>		BATTLETREE;

public:
	struct Data {
		SpaceType		_spaceType;
		int				_index;
		int 			_maxUser;
		int				_currentUser;
		int				_dungeonUser; // for world space
		int				_table_id;
		int				_difficulty;
		int				_boss_tid;
		int 			_dungeonTheme;
		int				_winnerGID;
		int				_totalDamageToBoss;
		bool			_bSendMapChange;
		int 			_enableCount;

		unsigned long _starttick;
		unsigned long _finishtick;

		int				_dropcounter;
		int				_acceptUserCount; // use party dungeon
		int				_refuseUserCount; // use party dungeon

		// PK
		int				_aliveUserCount;
		int				_killUserCount;
		int 			_mapTid;

		// PVP
		bool			_bPVPDummyUser;
		bool			_bPVPAmity;	// 친선대전 여부
		int				_PVPDummyUserSeq;
		int				_degree;

		bool			_isFirstStart;

		int				_reserveCount;

		int 			_worldBossSubType;
		int				_bDungeonBooster;

		Data() : _spaceType(SpaceType::__NONE__), _index(-1), _maxUser(0), _currentUser(0), _dungeonUser(0),
				_table_id(0), _difficulty(0),
				_boss_tid(0), _dungeonTheme(0),
				_winnerGID(0),
				_totalDamageToBoss(0), _bSendMapChange(false), _enableCount(0),
				_starttick(0), _finishtick(0),
				_dropcounter(0),
				_acceptUserCount(0), _refuseUserCount(0),
				_aliveUserCount(0), _killUserCount(0), _mapTid(-1), _bPVPDummyUser(false), _bPVPAmity(false), _PVPDummyUserSeq(-1), _degree(0)
		{

			_spaceType = SpaceType::__NONE__;
			_maxUser = 0;
			_currentUser = 0;
			_table_id = 0;
			_difficulty = 0;
			_boss_tid = 0;
			_dungeonTheme = 0;
			_winnerGID = 0;
			_totalDamageToBoss = 0;
			_bSendMapChange = false;
			_enableCount = 0;
			_starttick = 0;
			_finishtick = 0;
			_dropcounter = 0;
			_acceptUserCount = 0;
			_refuseUserCount = 0;
			_bPVPDummyUser = false;
			_bPVPAmity = false;
			_PVPDummyUserSeq = -1;

			_isFirstStart = true;

			_reserveCount = 0;
			_worldBossSubType = 0;
			_bDungeonBooster = 0;
		}


		void Clear()
		{
			_spaceType = SpaceType::__NONE__;

			_index = 0;
			_maxUser = 0;
			_currentUser = 0;
			_dungeonUser = 0; // for world space

			_table_id = 0;
			_difficulty = 0;

			_boss_tid = 0;
			_dungeonTheme = 0;

			_winnerGID = 0;

			_totalDamageToBoss = 0;
			_bSendMapChange = 0;
			_enableCount = 0;

			_starttick = 0;
			_finishtick = 0;

			_dropcounter = 0;

			_acceptUserCount = 0; // use party dungeon
			_refuseUserCount = 0; // use party dungeon


			_aliveUserCount = 0;
			_killUserCount = 0;

			_mapTid = 0;


			_bPVPDummyUser = 0;
			_PVPDummyUserSeq = 0;

			_degree = 0;

			_isFirstStart = true;

			_reserveCount = 0;
			_worldBossSubType = 0;
			_bDungeonBooster = 0;
		}
	};

public:
	Space();
	virtual 		~Space();

	void			Initialize();
	void 			Finalize();


	bool			Open(User * master, Data & clsData);
	Data &			GetData();

	bool			EnterUser(User * pUser, unsigned int posx=ConstPosX, unsigned int posy=ConstPosY);


	void			LeaveUser(User * pUser);


	User *			FindUser(int userSeq);
	bool			IsExistUser(int userSeq);

	void			SendAll(::Network::Packet * pPacket);
	void			SendAllExceptMe(::Network::Packet * pPacket, User * pUser);

	const USERTREE &	GetUserTree() const;

	User *			GetMaster();

	bool			AddMonster(Monster * pMonster);
	Monster *		GetMonster(int seq);
	void			RemoveMonster(int seq);
	int				GetMonsterCount();
	MONSTERTREE &	GetMonsterTree();
	MONSTERTREE &	GetDeadMonsterTree();

	//int 			GetSlaveCount();
	void			ClearMonsterTree();

	void			AddItem(Item * pItem);
	Item *			PopItem(int itemseq);
	const ITEMTREE &	GetItemTree();

	void					SetDetailInfoPacket(::Network::Packet * pPacket);
	::Network::Packet * 	GetDetailInfoPacket();

	void					MakeDungeonClearDetailInfoPacket();
	::Network::Packet *	GetDungeonClearDetailInfoPacket();

	void			MakePVPResultData(User * pUser, User * pOppUser);

	void			SetParty(Party * pParty);
	Party *		GetParty();

	int 			GetMonsterGID();
	int				GetSlaveGID();

	void			ClearDeadMonsterTree();


	void			SetEndDungeon(bool endDungeon);
	bool			GetEndEungeon() { return _endDungeon; }

	void			SetEndBattleRoyal(bool endBattleRoyal) { _endBattleRoyal = endBattleRoyal; }
	bool			GetEndBattleRoyal() { return _endBattleRoyal; }

	int				GetCCU();

	void			ReserveChannel(User * pUser);
	bool			FindReserveUser(uint32_t userseq);
	bool			EraseReserveUser(User * pUser);

	PKOUTPLAYUSERVECTOR & GetPKOutPlayUserVector() { return _pkOutPlayUser; }

	BATTLETREE &	GetBattleTree() { return _clsBattleTree; }

	NLogic::Battle *		FindBattle(int userSeq);


	void 			SetIndexer(Indexer * pIndexer) { _pIndexer = pIndexer; }
	Indexer *		GetIndexer() { return _pIndexer; }

	void 					SetIndexerWorldBoss(IndexerWorldBoss * pIndexer) { _pIndexerWorldBoss = pIndexer; }
	IndexerWorldBoss *	GetIndexerWorldBoss() { return _pIndexerWorldBoss; }

	void 						SetIndexerNewPartyRoomV2(IndexerNewPartyRoomV2 * pIndexer) { _pIndexNewPartyRoomV2 = pIndexer; }
	IndexerNewPartyRoomV2 *	GetIndexerNewPartyRoomV2() { return _pIndexNewPartyRoomV2; }


	bool			IsDungeon();
	bool			IsSingleDungeon();
	bool			IsPartyDungeon();
	bool			IsWorldBoss();

	void			SetPVPIndexer(IndexerPVP * pIndexer) { _pPVPIndexer = pIndexer; }
	IndexerPVP *	GetPVPIndexer() { return _pPVPIndexer; }

	void			SetPKIndexer(IndexerPK * pIndexer) { _pPKIndexer = pIndexer; }
	IndexerPK *		GetPKIndexer() { return _pPKIndexer; }

	int 			GetRefCount() { return _refCount; }

	bool			IsEventDungeon();

private:
	void			leaveWorld(User * pUser);

	bool			enterUserToWorld(User * pUser, unsigned int posx, unsigned int posy);
	bool			enterUserToDungeon(User * pUser);
	bool			enterUserToPVP(User * pUser);
	bool			enterUserToPK(User * pUser);
	bool			enterUserNewPartyRoom(User * pUser);
	bool			enterUserNewPVPRoom(User * pUser);
	bool			enterUserWorldBossRoom(User * pUser);

	void			leaveUserFromWorld(User * pUser);
	void			leaveUserFromDungeon(User * pUser);
	void			leaveUserFromPVP(User * pUser);
	bool			leaveUserFromPK(User * pUser);
	bool			leaveUserFromNewPartyRoom(User * pUser);
	void			leaveUserFromNewPVPRoom(User * pUser);
	void			leaveUserFromWorldBossRoom(User * pUser);

	bool			IsInPVP();

private:
	USERTREE 		_userTree;
	USERTREE		_leaveUserTree;
	Data 			_data;

	User *			_master;

	MONSTERTREE	_monsterTree;
	MONSTERTREE	_deadMonsterTree;
	INVITETREE		_inviteTree;
	ITEMTREE		_itemTree;

	::Network::Packet * 	pDetailInfoPacket;
	::Network::Packet * 	pDungeonClearDetailInfo;

	Party *		_party;

	int				_monsterGid;
	int				_slaveGid;

	bool			_endDungeon;
	bool			_endBattleRoyal;

	PKOUTPLAYUSERVECTOR _pkOutPlayUser;
	RESERVEVECTOR _reserveVector;

	BATTLETREE			_clsBattleTree;

	Indexer *			_pIndexer;
	IndexerPVP *		_pPVPIndexer;
	IndexerPK *			_pPKIndexer;
	IndexerWorldBoss *	_pIndexerWorldBoss;

	int 		_refCount;

	IndexerNewPartyRoomV2 * 		_pIndexNewPartyRoomV2;
};

} /*NLogic*/ } /* namespace ProjectZ */

#endif /* PROJECTZ_NLOGIC_SPACE_H_ */
